package util;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;

import kdd.DataTransfer;
import kdd.DbType;
import kdd.ItemRating;
import kdd.MetaData;
import kdd.UserData;

public class DataReader {

	public MetaData readStats(String filename) {

		MetaData trainingMetaData = new MetaData();

		try {
		    BufferedReader in = new BufferedReader(new FileReader(filename));
		    String str;
		    String name;
		    StringTokenizer st;
		    System.out.println("-----------------  LOADING STATS -----------------");
		    while ((str = in.readLine()) != null) {
		    	st = new StringTokenizer(str, "=");
		    	while (st.hasMoreTokens()) {
		    		name = st.nextToken();
		    		if (name.equals("nUsers")) {
		    			trainingMetaData.setTrainingTotalUsers(Integer.parseInt(st.nextToken()));
		    		} else if (name.equals("nItems")) {
		    			trainingMetaData.setTrainingTotalItems(Integer.parseInt(st.nextToken()));
		    		} else if (name.equals("nRatings")) {
		    			trainingMetaData.setDBallRatings(Integer.parseInt(st.nextToken()));
		    		} else if (name.equals("nTrainRatings")) {
		    			trainingMetaData.setTrainingTotalRatings(Integer.parseInt(st.nextToken()));
		    		} else if (name.equals("nProbeRatings")) {
		    			trainingMetaData.setValidationTotalRatings(Integer.parseInt(st.nextToken()));
		    		} else if (name.equals("nTestRatings")) {
		    			trainingMetaData.setTestTotalRatings(Integer.parseInt(st.nextToken()));
		    		}
		    	}
		    }
		    in.close();
		    System.out.println(trainingMetaData);

		} catch (IOException e) {
			System.err.println("Error: " + e.getMessage());
		}
		return trainingMetaData;
	}

	public DataTransfer readTrack1DBFromTextFiles(String filePrefs, DbType dbType, MetaData metaData) {

		MetaData pMetaData = metaData;
		//ArrayList ppItemRatings = new ArrayList<ItemRating>();
		ItemRating[] ppItemRatings = null;
		UserData[] pUsersData = null;
		int usrId, itemId, score;
		int total_ratings = 0;
		double total_scores=0;

		switch (dbType) {
			case TRAINING:
				total_ratings = pMetaData.getTrainingTotalRatings();
				System.out.println("TRAINING total_ratings - " + total_ratings);
				break;

			case VALIDATION:
				total_ratings = pMetaData.getValidationTotalRatings();
//				ppItemRatings = &(pItemRatings_validation);
				System.out.println("VALIDATION total_ratings - " +total_ratings);
				break;

			case TEST:
				total_ratings = pMetaData.getTestTotalRatings();
//				ppItemRatings = &(pItemRatings_test);
				System.out.println("TEST total_ratings - " + total_ratings);
				break;

			default:
				break;
		}

		int[] pItemsArr = new int[pMetaData.getTrainingTotalItems()];
		for(int i=0;i<pMetaData.getTrainingTotalItems();i++){
			pItemsArr[i]=0;
		}
		int prevUser = -1;
		// In the Training DB we allocate also the users array
		if (DbType.TRAINING == dbType) {
			pUsersData = new UserData[pMetaData.getTrainingTotalUsers() + 1];
			System.out.println("pUsersData length - " + pUsersData.length);
		}


		ppItemRatings = new ItemRating[total_ratings];
		//ppItemRatings = new ItemRating[250000000];

		usrId = 0;

		try {
		    BufferedReader in = new BufferedReader(new FileReader(filePrefs));
		    String str;
		    StringTokenizer st;

		    int RATINGS_PER_USER_VALIDATION = 4;
		    int RATINGS_PER_USER_TEST = 6;
		    //Run on users:
		    while ((str = in.readLine()) != null) {
		    	int nUserRatings = 0;
		    	st = new StringTokenizer(str, "|");
		    	while (st.hasMoreTokens()) {
		    		// Get user id:
		    		usrId = Integer.parseInt(st.nextToken());
		    		if ( ++prevUser != usrId) {
		    			System.out.println("Users are un-ordered!! previous user was:" + prevUser + " this user is:" + usrId);
		    			return null;
		    		}
		    		prevUser = usrId;
		    		pMetaData.setNUsers( pMetaData.getNUsers() + 1);
		    		// Get number of ratings:
		    		nUserRatings = Integer.parseInt(st.nextToken());

		    		if(DbType.TRAINING == dbType) {
		    			assert(nUserRatings>0) : "bad nUserRatings: " + nUserRatings;
		    			UserData userData = pUsersData[usrId];
		    			if (userData == null) userData = new UserData();
		    			userData.setRatings(nUserRatings);
		    			pUsersData[usrId] = userData;
		    		}
		    		else if (DbType.VALIDATION == dbType ) {
		    			assert(RATINGS_PER_USER_VALIDATION==nUserRatings) : "bad RATINGS_PER_USER_VALIDATION: " + nUserRatings;
		    		}
		    		else if(DbType.TEST == dbType) {
		    			assert(RATINGS_PER_USER_TEST==nUserRatings) : "bad RATINGS_PER_USER_TEST: " + nUserRatings;
		    		}

		    	}

	    		//Read the user's ratings:
	    		for(int rating_idx=0; rating_idx<nUserRatings; rating_idx++) {
	    			str = in.readLine();
	    			st = new StringTokenizer(str,"\t");
	    			//Get the item ID:
	    			itemId = Integer.parseInt(st.nextToken());
	    			assert(itemId<pMetaData.getTrainingTotalItems()) : "bad trainingTotalItems: " + nUserRatings;
	    			pItemsArr[itemId]=1;

	    			ItemRating ir = new ItemRating();
	    			ir.setItem(itemId);

	    			if(DbType.TEST != dbType) {
	    				//Get the score:
	    				score = Integer.parseInt(st.nextToken());
	    				assert( score>=0 && score<=100) : "bad score: " + score;
	    				ir.setScore(score);
	    				total_scores+=score;
	    			} else {
	    				ir.setScore(0);
	    			}
	    			ppItemRatings[pMetaData.getNRecords()] = ir;
	    			pMetaData.setNRecords(pMetaData.getNRecords() + 1); //Counts the number of records (ratings)

	    			/*
	    			//Get the day and time:
	    			char *dayStr = 0; char *timeStr = 0; char *hourStr = 0; char *minuteStr = 0;
	    			unsigned int day=0, hour=0, minute=0;

	    			dayStr    = strtok(NULL,"\t");
	    			day = atoi(dayStr);

	    			timeStr    = strtok(NULL,"\t");

	    			hourStr    = strtok(timeStr,":");
	    			hour = atoi(hourStr);
	    			assert((hour>=0)&&(hour<=23));

	    			minuteStr  = strtok(NULL,":");
	    			minute = atoi(minuteStr);
	    			assert((minute>=0)&&(minute<=59));
	    			*/
	    		}
		    }
		    in.close();


		    pMetaData.setTotalMeanScore(total_scores/pMetaData.getNRecords());
			//Update MetaData:
			for( int i=0; i<pMetaData.getTrainingTotalItems(); i++) {
				pMetaData.setNItems(pMetaData.getNItems() + pItemsArr[i]);
			}

		    System.out.println("Done reading ratings!");
		    System.out.println("----  SUMMARY:  ----");
		    System.out.println("  Users:" + pMetaData.getNUsers() + " Records:" + pMetaData.getNRecords() + " Items:" + pMetaData.getNItems());
		    System.out.println("  Mean score: " + pMetaData.getTotalMeanScore());

		} catch (IOException e) {
			System.err.println("Error: " + e.getMessage());
		}
		return new DataTransfer(ppItemRatings, pUsersData);
	}
}
